home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 23 Character Animation / SkinnedMesh / Shaders / Ssao.hlsl < prev    next >
Encoding:
Text File  |  2016-03-02  |  6.3 KB  |  201 lines

  1. //=============================================================================
  2. // Ssao.hlsl by Frank Luna (C) 2015 All Rights Reserved.
  3. //=============================================================================
  4.  
  5. cbuffer cbSsao : register(b0)
  6. {
  7.     float4x4 gProj;
  8.     float4x4 gInvProj;
  9.     float4x4 gProjTex;
  10.     float4   gOffsetVectors[14];
  11.  
  12.     // For SsaoBlur.hlsl
  13.     float4 gBlurWeights[3];
  14.  
  15.     float2 gInvRenderTargetSize;
  16.  
  17.     // Coordinates given in view space.
  18.     float    gOcclusionRadius;
  19.     float    gOcclusionFadeStart;
  20.     float    gOcclusionFadeEnd;
  21.     float    gSurfaceEpsilon;
  22.  
  23.     
  24. };
  25.  
  26. cbuffer cbRootConstants : register(b1)
  27. {
  28.     bool gHorizontalBlur;
  29. };
  30.  
  31. // Nonnumeric values cannot be added to a cbuffer.
  32. Texture2D gNormalMap    : register(t0);
  33. Texture2D gDepthMap     : register(t1);
  34. Texture2D gRandomVecMap : register(t2);
  35.  
  36. SamplerState gsamPointClamp : register(s0);
  37. SamplerState gsamLinearClamp : register(s1);
  38. SamplerState gsamDepthMap : register(s2);
  39. SamplerState gsamLinearWrap : register(s3);
  40.  
  41. static const int gSampleCount = 14;
  42.  
  43. static const float2 gTexCoords[6] =
  44. {
  45.     float2(0.0f, 1.0f),
  46.     float2(0.0f, 0.0f),
  47.     float2(1.0f, 0.0f),
  48.     float2(0.0f, 1.0f),
  49.     float2(1.0f, 0.0f),
  50.     float2(1.0f, 1.0f)
  51. };
  52.  
  53. struct VertexOut
  54. {
  55.     float4 PosH : SV_POSITION;
  56.     float3 PosV : POSITION;
  57.     float2 TexC : TEXCOORD0;
  58. };
  59.  
  60. VertexOut VS(uint vid : SV_VertexID)
  61. {
  62.     VertexOut vout;
  63.  
  64.     vout.TexC = gTexCoords[vid];
  65.  
  66.     // Quad covering screen in NDC space.
  67.     vout.PosH = float4(2.0f*vout.TexC.x - 1.0f, 1.0f - 2.0f*vout.TexC.y, 0.0f, 1.0f);
  68.  
  69.     // Transform quad corners to view space near plane.
  70.     float4 ph = mul(vout.PosH, gInvProj);
  71.     vout.PosV = ph.xyz / ph.w;
  72.  
  73.     return vout;
  74. }
  75.  
  76. // Determines how much the sample point q occludes the point p as a function
  77. // of distZ.
  78. float OcclusionFunction(float distZ)
  79. {
  80.     //
  81.     // If depth(q) is "behind" depth(p), then q cannot occlude p.  Moreover, if 
  82.     // depth(q) and depth(p) are sufficiently close, then we also assume q cannot
  83.     // occlude p because q needs to be in front of p by Epsilon to occlude p.
  84.     //
  85.     // We use the following function to determine the occlusion.  
  86.     // 
  87.     //
  88.     //       1.0     -------------\
  89.     //               |           |  \
  90.     //               |           |    \
  91.     //               |           |      \ 
  92.     //               |           |        \
  93.     //               |           |          \
  94.     //               |           |            \
  95.     //  ------|------|-----------|-------------|---------|--> zv
  96.     //        0     Eps          z0            z1        
  97.     //
  98.     
  99.     float occlusion = 0.0f;
  100.     if(distZ > gSurfaceEpsilon)
  101.     {
  102.         float fadeLength = gOcclusionFadeEnd - gOcclusionFadeStart;
  103.         
  104.         // Linearly decrease occlusion from 1 to 0 as distZ goes 
  105.         // from gOcclusionFadeStart to gOcclusionFadeEnd.    
  106.         occlusion = saturate( (gOcclusionFadeEnd-distZ)/fadeLength );
  107.     }
  108.     
  109.     return occlusion;    
  110. }
  111.  
  112. float NdcDepthToViewDepth(float z_ndc)
  113. {
  114.     // z_ndc = A + B/viewZ, where gProj[2,2]=A and gProj[3,2]=B.
  115.     float viewZ = gProj[3][2] / (z_ndc - gProj[2][2]);
  116.     return viewZ;
  117. }
  118.  
  119. float4 PS(VertexOut pin) : SV_Target
  120. {
  121.     // p -- the point we are computing the ambient occlusion for.
  122.     // n -- normal vector at p.
  123.     // q -- a random offset from p.
  124.     // r -- a potential occluder that might occlude p.
  125.  
  126.     // Get viewspace normal and z-coord of this pixel.  
  127.     float3 n = gNormalMap.SampleLevel(gsamPointClamp, pin.TexC, 0.0f).xyz;
  128.     float pz = gDepthMap.SampleLevel(gsamDepthMap, pin.TexC, 0.0f).r;
  129.     pz = NdcDepthToViewDepth(pz);
  130.  
  131.     //
  132.     // Reconstruct full view space position (x,y,z).
  133.     // Find t such that p = t*pin.PosV.
  134.     // p.z = t*pin.PosV.z
  135.     // t = p.z / pin.PosV.z
  136.     //
  137.     float3 p = (pz/pin.PosV.z)*pin.PosV;
  138.     
  139.     // Extract random vector and map from [0,1] --> [-1, +1].
  140.     float3 randVec = 2.0f*gRandomVecMap.SampleLevel(gsamLinearWrap, 4.0f*pin.TexC, 0.0f).rgb - 1.0f;
  141.  
  142.     float occlusionSum = 0.0f;
  143.     
  144.     // Sample neighboring points about p in the hemisphere oriented by n.
  145.     for(int i = 0; i < gSampleCount; ++i)
  146.     {
  147.         // Are offset vectors are fixed and uniformly distributed (so that our offset vectors
  148.         // do not clump in the same direction).  If we reflect them about a random vector
  149.         // then we get a random uniform distribution of offset vectors.
  150.         float3 offset = reflect(gOffsetVectors[i].xyz, randVec);
  151.     
  152.         // Flip offset vector if it is behind the plane defined by (p, n).
  153.         float flip = sign( dot(offset, n) );
  154.         
  155.         // Sample a point near p within the occlusion radius.
  156.         float3 q = p + flip * gOcclusionRadius * offset;
  157.         
  158.         // Project q and generate projective tex-coords.  
  159.         float4 projQ = mul(float4(q, 1.0f), gProjTex);
  160.         projQ /= projQ.w;
  161.  
  162.         // Find the nearest depth value along the ray from the eye to q (this is not
  163.         // the depth of q, as q is just an arbitrary point near p and might
  164.         // occupy empty space).  To find the nearest depth we look it up in the depthmap.
  165.  
  166.         float rz = gDepthMap.SampleLevel(gsamDepthMap, projQ.xy, 0.0f).r;
  167.         rz = NdcDepthToViewDepth(rz);
  168.  
  169.         // Reconstruct full view space position r = (rx,ry,rz).  We know r
  170.         // lies on the ray of q, so there exists a t such that r = t*q.
  171.         // r.z = t*q.z ==> t = r.z / q.z
  172.  
  173.         float3 r = (rz / q.z) * q;
  174.         
  175.         //
  176.         // Test whether r occludes p.
  177.         //   * The product dot(n, normalize(r - p)) measures how much in front
  178.         //     of the plane(p,n) the occluder point r is.  The more in front it is, the
  179.         //     more occlusion weight we give it.  This also prevents self shadowing where 
  180.         //     a point r on an angled plane (p,n) could give a false occlusion since they
  181.         //     have different depth values with respect to the eye.
  182.         //   * The weight of the occlusion is scaled based on how far the occluder is from
  183.         //     the point we are computing the occlusion of.  If the occluder r is far away
  184.         //     from p, then it does not occlude it.
  185.         // 
  186.         
  187.         float distZ = p.z - r.z;
  188.         float dp = max(dot(n, normalize(r - p)), 0.0f);
  189.         float occlusion = dp * OcclusionFunction(distZ);
  190.         
  191.         occlusionSum += occlusion;
  192.     }
  193.     
  194.     occlusionSum /= gSampleCount;
  195.     
  196.     float access = 1.0f - occlusionSum;
  197.  
  198.     // Sharpen the contrast of the SSAO map to make the SSAO affect more dramatic.
  199.     return saturate(pow(access, 2.0f));
  200. }
  201.